iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
Software Development

Port Alpine Linux to open source RISC-V platform系列 第 6

musl libc 簡介與其 porting(五) Knocking on Heaven's Door

  • 分享至 

  • xImage
  •  

C runtime/lib 通常都會有一個測試自己實做正確性的testsuite,像在glibc內部、就有兩套測試,一套是檢驗正確性、回歸測試用的testsuite,另外一套是效能的benchtest;而musl-libc的同等物叫作libc-test的testsuite,目前由libm的作者 Nagy 在進行維運。

然而,在測試libc-test之前,我們先來處理一件事情會比較好,那就是 dynamic linking/loading 的問題。因為musl-libc的檢驗方式,會測試 statically-linked build, statically-linked run, dynamically-linked build, dynamically-linked run 這四個排列組合。而且因為他的編譯方式,我們先初步bringup dynamica,會有意外的好處。

為了打通dynamic linking/loading,我們必須修正原本來自RV64平台 arch/riscv32/reloc.h 中的relocation type定義:

diff ./arch/riscv32/reloc.h ./arch/riscv64/reloc.h
9c9
< #define LDSO_ARCH "riscv32" RISCV_FP_SUFFIX
---
> #define LDSO_ARCH "riscv64" RISCV_FP_SUFFIX
13c13
< #define REL_SYMBOLIC    R_RISCV_32
---
> #define REL_SYMBOLIC    R_RISCV_64
17,19c17,19
< #define REL_DTPMOD      R_RISCV_TLS_DTPMOD32
< #define REL_DTPOFF      R_RISCV_TLS_DTPREL32
< #define REL_TPOFF       R_RISCV_TLS_TPREL32
---
> #define REL_DTPMOD      R_RISCV_TLS_DTPMOD64
> #define REL_DTPOFF      R_RISCV_TLS_DTPREL64
> #define REL_TPOFF       R_RISCV_TLS_TPREL64

緊接著,我們在編譯的時候需要加上對應的參數:

CROSS_COMPILE=riscv32-linux- configure --target=riscv32 --enable-shared --enable-debug --prefix=/path/to/install
DESTDIR=/path/to/install make install

在編譯時,可以觀察到除了有link出shared library libc.so外,還有一份 musl-gcc 的檔案被寫了出去。
此時我們把他打開來一探究境:

#!/bin/sh
exec "${REALGCC:-riscv32-linux-gcc}" "$@" -specs "/path/to/install/musl-gcc.specs"

簡單說,他是會去呼叫configure時,吃進去的 compiler name,並且使用特殊的spec file:

%rename cpp_options old_cpp_options

*cpp_options:
-nostdinc -isystem /path/to/install/include -isystem include%s %(old_cpp_options)

*cc1:
%(cc1_cpu) -nostdinc -isystem /path/to/install/include -isystem include%s

*link_libgcc:
-L/path/to/install/lib -L .%s

*libgcc:
libgcc.a%s %:if-exists(libgcc_eh.a%s)

*startfile:
%{!shared: /path/to/install/lib/Scrt1.o} /path/to/install/lib/crti.o crtbeginS.o%s

*endfile:
crtendS.o%s /path/to/lib/crtn.o

*link:
-dynamic-linker /lib/ld-musl-riscv32.so.1 -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic}

*esp_link:


*esp_options:


*esp_cpp_options:

簡單來說,這份檔案是會讓gcc執行時,會在對應的使用情境下,開啟不同的編譯選項,例如nostdinc,所以不會去尋找toolchain stage2時設定的C runtime/library,CRT檔案在何方、以及最重要的 — — 在load time時會把so放好、做好symbol resolve的dynamic-linker 。
這時,我們可以非常快速的補正一下上面對應的路徑,到你安裝的位置上,從此之後就能非常輕鬆地使用 musl-gcc這個wrapper來編譯程式。

於是,頭號拿來編的對象就是,libc-test ~~~
按照readme複製一份config.mak出來,

cp config.mak.def config.mak

接著修改Makefile中的RUN_TESTqemu-riscv32,並且開始編譯/執行:

CC=musl-gcc make all run

編譯、運行完libc-test號,我們發現有兩個syscall目前有狀況,直接壞在testsuite的大門上,他們便是:
sigtimedwait以及waitpid

第一件事情比較簡單,我們快速翻閱qemu的./linux-user/riscv/syscall32_nr.h 發現,在riscv32跟其他32平台上,該syscall已經被重新定義成sigtimedwait_time64,快速修正一下:

diff --git a/arch/riscv32/bits/syscall.h.in b/arch/riscv32/bits/syscall.h.in
index 480adc58..67070141 100644
--- a/arch/riscv32/bits/syscall.h.in
+++ b/arch/riscv32/bits/syscall.h.in
@@ -133,7 +134,8 @@
 #define __NR_rt_sigaction 134
 #define __NR_rt_sigprocmask 135
 #define __NR_rt_sigpending 136
-#define __NR_rt_sigtimedwait 137
+//#define __NR_rt_sigtimedwait 137
+#define __NR_rt_sigtimedwait_time64 421
 #define __NR_rt_sigqueueinfo 138
 #define __NR_rt_sigreturn 139
 #define __NR_setpriority 140
diff --git a/arch/riscv32/syscall_arch.h b/arch/riscv32/syscall_arch.h
index ecf2b8a5..5f8760f7 100644
--- a/arch/riscv32/syscall_arch.h
+++ b/arch/riscv32/syscall_arch.h
@@ -2,6 +2,7 @@
 #define SYSCALL_FADVISE_6_ARG
 #define SYSCALL_IPC_BROKEN_MODE
 #define SYS_clock_gettime SYS_clock_gettime64
+#define SYS_rt_sigtimedwait SYS_rt_sigtimedwait_time64

第二件事情就複雜了,簡單說Linux kernel 32bit平台在搬到64bit time_t後,wait4這個syscall直接被幹掉了。而新的waitid其實跟waitpid、wait4都差很遠。
萬幸的是我們可以找到glibc那邊有一組可以用、但是沒有被收進去的patch: https://sourceware.org/legacy-ml/libc-alpha/2019-09/msg00443.html

具體修正長這樣:

 #include <sys/wait.h>
+#include <signal.h>
 #include "syscall.h"
 
 pid_t waitpid(pid_t pid, int *status, int options)
 {
+    #if __riscv_xlen != 32
        return syscall_cp(SYS_wait4, pid, status, options, 0);
+    #else // generic wait4
+       pid_t ret;
+       idtype_t idtype = P_PID;
+       siginfo_t infop;
+
+       if (pid < -1)
+         {
+           idtype = P_PGID;
+           pid *= -1;
+         }
+       else if (pid == -1)
+         {
+           idtype = P_ALL;
+         }
+       else if (pid == 0)
+         {
+           /* Linux Kernels 5.4+ support pid 0 with P_PGID to specify wait on
+            * the current PID's group. Earlier kernels will return -EINVAL.
+            */
+           idtype = P_PGID;
+         }
+
+       options |= WEXITED;
+
+       ret = syscall_cp (SYS_waitid, idtype, pid, &infop, options, 0);
+       //ret = SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, NULL);
+
+       if (ret < 0)
+         {
+           return ret;
+         }
+
+       if (status)
+         {
+           *status = 0;
+           switch (infop.si_code)
+               {
+               case CLD_EXITED:
+                       *status = infop.si_status << 8;
+                       break;
+               case CLD_DUMPED:
+                       *status = 0x80;
+                       /* Fallthrough */
+               case CLD_KILLED:
+                       *status |= infop.si_status;
+                       break;
+               case CLD_TRAPPED:
+               case CLD_STOPPED:
+                       *status = infop.si_status << 8 | 0x7f;
+                       break;
+               case CLD_CONTINUED:
+                       *status = 0xffff;
+                       break;
+               }
+         }
+
+       return infop.si_pid;
+    #endif // rv32 waitid hack
 }

在上了這兩組patch後,我們至少敲得進大門了QQ

$ qemu-riscv32 ./src/common/runtest.exe -w /usr/bin/qemu-riscv32 -t 1 ./src/functional/argv.exe
$ echo $?
0

然而,一放下去給他全跑:

RUN_WRAP=/usr/bin/qemu-riscv32 make run

馬上又是debug地獄了XD
先讓我富堅一下XDDDDD


上一篇
musl libc 簡介與其 porting(四)Nobody speak.
下一篇
musl libc 簡介與其 porting(六)Busy Box Band
系列文
Port Alpine Linux to open source RISC-V platform30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言